import { Injectable, Logger, BadRequestException } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import fetch from 'node-fetch';

// AI message interface
export interface AIMessage {
  role: 'system' | 'user' | 'assistant';
  content: string;
}

// AI response interface
export interface AIResponse {
  content: string;
  usage?: {
    promptTokens: number;
    completionTokens: number;
    totalTokens: number;
  };
  model: string;
  provider: 'qwen';
}

// Text-to-speech response interface
export interface TTSResponse {
  audioUrl: string;
  duration: number;
  format: string;
}

// Speech-to-text response interface
export interface ASRResponse {
  text: string;
  confidence: number;
  duration: number;
  language: string;
}

@Injectable()
export class AIService {
  private readonly logger = new Logger(AIService.name);
  private elevenLabsApiKey: string;
  private deepgramApiKey: string;
  private qwenApiKey: string;

  constructor(private configService: ConfigService) {
    this.elevenLabsApiKey = this.configService.get<string>('ELEVENLABS_API_KEY') || '';
    this.deepgramApiKey = this.configService.get<string>('DEEPGRAM_API_KEY') || '';
    this.qwenApiKey = this.configService.get<string>('QWEN_API_KEY') || '';
    
    this.logger.log('AI Service initialized with Qwen LLM');
  }

  // Generate AI response
  async generateResponse(
    messages: AIMessage[],
    personaPrompt: string,
    model: string = 'qwen-turbo'
  ): Promise<AIResponse> {
    if (!this.qwenApiKey) {
      throw new BadRequestException('Qwen API key not configured');
    }

    try {
      const systemMessage: AIMessage = {
        role: 'system',
        content: personaPrompt,
      };

      const response = await fetch('https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation', {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${this.qwenApiKey}`,
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          model,
          input: {
            messages: [systemMessage, ...messages],
          },
          parameters: {
            max_tokens: 1000,
            temperature: 0.7,
          },
        }),
      });

      if (!response.ok) {
        throw new Error(`Qwen API error: ${response.statusText}`);
      }

      const result = await response.json() as any;
      const content = result.output?.text || result.output?.choices?.[0]?.message?.content;

      if (!content) {
        throw new BadRequestException('No response generated from Qwen');
      }

      return {
        content,
        usage: result.usage ? {
          promptTokens: result.usage.input_tokens || 0,
          completionTokens: result.usage.output_tokens || 0,
          totalTokens: result.usage.total_tokens || 0,
        } : undefined,
        model: result.model || model,
        provider: 'qwen',
      };
    } catch (error) {
      this.logger.error('Failed to generate Qwen response:', error);
      throw new BadRequestException('Failed to generate AI response');
    }
  }

  // Stream AI response generation (not supported yet)
  async generateStreamResponse(
    messages: AIMessage[],
    personaPrompt: string,
    model: string = 'qwen-turbo'
  ): Promise<AsyncGenerator<string, void, unknown>> {
    throw new BadRequestException('Streaming not supported with domestic LLM providers');
  }

  // Text preprocessing for optimized TTS effects
  private preprocessTextForTTS(text: string, language: string = 'en'): string {
    if (language === 'zh') {
      // Chinese punctuation replacement
      return text
        .replace(/，/g, ', ')
        .replace(/。/g, '. ')
        .replace(/！/g, '! ')
        .replace(/？/g, '? ')
        .replace(/；/g, '; ')
        .replace(/：/g, ': ')
        .replace(/"/g, '" ')
        .replace(/"/g, '" ')
        .replace(/'/g, "' ")
        .replace(/'/g, "' ")
        .replace(/（/g, ' (')
        .replace(/）/g, ') ')
        .replace(/【/g, ' [')
        .replace(/】/g, '] ')
        .replace(/《/g, ' <')
        .replace(/》/g, '> ')
        .replace(/\s+/g, ' ') // Merge multiple spaces
        .trim();
    } else {
      // English mode: basic cleanup
      return text
        .replace(/\s+/g, ' ') // Merge multiple spaces
        .trim();
    }
  }

  // Text-to-speech conversion
  async textToSpeech(
    text: string,
    voice: string = '21m00Tcm4TlvDq8ikWAM', // Rachel voice ID
    format: string = 'mp3',
    language: string = 'en'
  ): Promise<TTSResponse> {
    if (!this.elevenLabsApiKey) {
      throw new BadRequestException('ElevenLabs API not configured');
    }

    try {
      // Preprocess text
      const processedText = this.preprocessTextForTTS(text, language);
      const response = await fetch(`https://api.elevenlabs.io/v1/text-to-speech/${voice}`, {
        method: 'POST',
        headers: {
          'Accept': 'audio/mpeg',
          'Content-Type': 'application/json',
          'xi-api-key': this.elevenLabsApiKey,
        },
        body: JSON.stringify({
          text: processedText,
          model_id: 'eleven_multilingual_v2',
          voice_settings: {
            stability: 0.6,
            similarity_boost: 0.7,
            style: 0.2,
            use_speaker_boost: true,
          },
        }),
      });

      if (!response.ok) {
        throw new Error(`TTS API error: ${response.statusText}`);
      }

      const audioBuffer = await response.arrayBuffer();
      const audioUrl = `data:audio/mpeg;base64,${Buffer.from(audioBuffer).toString('base64')}`;

      return {
        audioUrl,
        duration: audioBuffer.byteLength / 16000, // Estimated duration
        format: 'mp3',
      };
    } catch (error) {
      this.logger.error('Failed to generate TTS:', error);
      throw new BadRequestException('Failed to generate speech');
    }
  }

  // Speech-to-text conversion
  async speechToText(
    audioBuffer: ArrayBuffer,
    language: string = 'en',
    mimeType: string = 'audio/wav'
  ): Promise<ASRResponse> {
    if (!this.deepgramApiKey) {
      throw new BadRequestException('Deepgram API not configured');
    }

    try {
      const response = await fetch(`https://api.deepgram.com/v1/listen?language=${encodeURIComponent(language)}`, {
        method: 'POST',
        headers: {
          'Authorization': `Token ${this.deepgramApiKey}`,
          'Content-Type': mimeType || 'audio/wav',
        },
        body: Buffer.from(audioBuffer),
      });

      if (!response.ok) {
        const errorText = await response.text();
        this.logger.error(`ASR API error: ${response.status} - ${errorText}`);
        throw new BadRequestException(`ASR provider error: ${errorText}`);
      }

      const result = await response.json() as any;
      const transcript = result.results?.channels?.[0]?.alternatives?.[0];

      if (!transcript) {
        this.logger.error('ASR success but no transcript found', { result });
        throw new BadRequestException('No transcript found. Ensure audio contains clear speech and correct mimeType.');
      }

      return {
        text: transcript.transcript,
        confidence: transcript.confidence,
        duration: result.metadata?.duration || 0,
        language: result.results?.language || language,
      };
    } catch (error) {
      this.logger.error('Failed to process ASR:', error);
      if (error instanceof BadRequestException) throw error;
      throw new BadRequestException('Failed to process speech');
    }
  }


  // Check service health status
  async checkServiceHealth(): Promise<{
    qwen: boolean;
    elevenlabs: boolean;
    deepgram: boolean;
  }> {
    const health = {
      qwen: !!this.qwenApiKey,
      elevenlabs: !!this.elevenLabsApiKey,
      deepgram: !!this.deepgramApiKey,
    };

    // Test Qwen connection
    if (this.qwenApiKey) {
      try {
        const response = await fetch('https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation', {
          method: 'POST',
          headers: {
            'Authorization': `Bearer ${this.qwenApiKey}`,
            'Content-Type': 'application/json',
          },
          body: JSON.stringify({
            model: 'qwen-turbo',
            input: {
              messages: [
                {
                  role: 'user',
                  content: 'test'
                }
              ]
            },
            parameters: {
              max_tokens: 10,
              temperature: 0.7,
            },
          }),
        });

        if (response.ok) {
          this.logger.log('Qwen health check passed');
        } else {
          throw new Error(`Qwen API error: ${response.statusText}`);
        }
      } catch (e: any) {
        this.logger.warn(`Qwen health check failed: ${e?.message || e}`);
        health.qwen = false;
      }
    }

    return health;
  }

}
